package clases;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class GeneradorDeCasos {
	
	int CANTIDAD_DE_CASOS = 100;
	
	
	static int cantidadDeVariablesMax = 10;
	static int cantidadDeClausulasMax = 10;
	static int variacionDelRandom  = 100; //variacionDelRandom tiene quser menor que cantidad de variables, mientras mas chico mas varibles toma
	static int cantDeCasos = 3;
	
	
	public static void main(String[] args) throws Exception {
		GeneradorDeCasos g = new GeneradorDeCasos();
		ArrayList<CasoDePrueba> casos = new ArrayList<CasoDePrueba>();
		for (int i = 1; i < cantDeCasos; i++) {
			for (int j = 1; j < cantidadDeVariablesMax+1; j++) {
				casos.add(g.generarCasoDePruebaBIEN(j,cantidadDeClausulasMax, variacionDelRandom));
			}
		}
		g.escribirCasoDePrueba(casos);
		
		/*GeneradorDeCasos g = new GeneradorDeCasos();
		g.hacerCasos();*/
		
	}
	
	public void generarCasosExacto() throws Exception{
		
		
		this.hacerCasos(cantDeCasos, cantidadDeVariablesMax, cantidadDeClausulasMax, variacionDelRandom);
		//this.hacerCasos();
		
	}
	
	
	private void hacerCasos() throws Exception {
	
	
		int cantidadDeVariables = 10;
		int cantidadDeClausulas = 100;
		int variacionDelRandom  = 8; //fRECUENCIA DE QUE ESTEN LAS VARIABLES MAYOR NUMERO MENOS VECES APARECEN en cada clausula
		
		BufferedWriter bw = new BufferedWriter(new FileWriter("Tp3.in" ));
		//Itero casos de prueba
		for (int j = 1; j < CANTIDAD_DE_CASOS + 1; j++) {
			
			//Cantidad de variables por 10 son la cantidad de clausulas
			bw.append(cantidadDeClausulas + " " + cantidadDeVariables);
			bw.newLine();
			for (int k = 0; k < cantidadDeClausulas; k++) {
				StringBuffer sb = new StringBuffer();
				int contadorEstan = 0;
				//Random entre 0 y variacionDelRandom
				int random = (int) (Math.floor(Math.random() * 10) % variacionDelRandom) + 1;
				//Itero cantidad de variables y con el random me fijo si puedo ponerlas o no
				for (int l = 1; l < cantidadDeVariables; l++) {
					//Nuevamente un random para ver si poner o no la variable, pero siempre pongo hasta cantidad de variables como max
					if(Math.floor(Math.random() * 10) % random == 0) {
						contadorEstan++;
						//Si es par la agrego como positiva, sino negativa
						if(Math.floor(Math.random() * 10) % 2 == 0) {
							sb.append(" " +l + " ");
						} else {
							sb.append(" " + -1 * l + " ");
						}
					}
				
				}
				bw.append(contadorEstan + sb.toString());
				bw.newLine();
			
			}
			
		}
		
		bw.append("-1 -1");
		bw.close();
	}
	
	
	
	private void hacerCasos(int cantDeCasos,int cantidadDeVariables,int cantidadDeClausulas,int variacionDelRandom) throws Exception {
		BufferedWriter bw = new BufferedWriter(new FileWriter("Tp3.in"));

		// Itero casos de prueba
		for (int j = 1; j < cantDeCasos + 1; j++) {
			// Cantidad de variables por 10 son la cantidad de clausulas

			for (int u = 1; u < cantidadDeVariables; u++) {

				int random = (int) (Math.floor(Math.random() * cantidadDeVariables) % variacionDelRandom) + 1;
				bw.append(cantidadDeClausulas + " " + u);
				bw.newLine();
				for (int k = 0; k < cantidadDeClausulas; k++) {
					StringBuffer sb = new StringBuffer();
					int contadorEstan = 0;
					
					for (int l = 1; l < u+1; l++) { //Pongo #varibles
						
						 if (Math.floor(Math.random() * cantidadDeVariables) % random == 0) {
						contadorEstan++;
						// Si es par la agrego como positiva, sino negativa
							if (Math.floor(Math.random() * 10) % 2 == 0) {
								sb.append(" " + l + " ");
							} else {
								sb.append(" " + -1 * l + " ");
							}
						}

					}
					bw.append(contadorEstan + sb.toString());
					bw.newLine();

				}

			}
			
		}
		
		bw.append("-1 -1");
		bw.close();
	}
	
	private void hacerCasosVariandoClausulas(int cantDeCasos,int cantidadDeVariables,int cantidadDeClausulas,int variacionDelRandom) throws Exception {
		BufferedWriter bw = new BufferedWriter(new FileWriter("Tp3VariandoClausulas.in"));
		
		for (int j = 1; j < cantDeCasos + 1; j++) {		
			//Primero meto todas las variables en clausulas al azar!
			//Dps sigo metiendo variables, pero ya asegurandome que meti al menos 1 en alguna clausula
			for (int u = 1; u < cantidadDeClausulas; u++) {
				
				int random = (int) (Math.floor(Math.random() * cantidadDeVariables) % variacionDelRandom) + 1;
				bw.append(u + " " + cantidadDeVariables);
				bw.newLine();

				for (int k = 0; k < cantidadDeVariables; k++) {
					StringBuffer sb = new StringBuffer();
					int contadorEstan = 0;
					
					for (int l = 1; l < cantidadDeVariables+1; l++) { //Pongo #clausulas
						
						 if (Math.floor(Math.random() * cantidadDeVariables) % random == 0) {
						contadorEstan++;
						// Si es par la agrego como positiva, sino negativa
							if (Math.floor(Math.random() * 10) % 2 == 0) {
								sb.append(" " + l + " ");
							} else {
								sb.append(" " + -1 * l + " ");
							}
						}

					}
					bw.append(contadorEstan + sb.toString());
					bw.newLine();

				}

			}
			
		}
		
		bw.append("-1 -1");
		bw.close();
	}
	
	
	public CasoDePrueba generarCasoDePruebaBIEN(int cantidadDeVariables,int cantidadDeClausulas,int variacionDelRandom){

		//Control
		if(variacionDelRandom>cantidadDeVariables){
			variacionDelRandom=cantidadDeVariables;
		}
		
		CasoDePrueba caso = new CasoDePrueba(cantidadDeClausulas,cantidadDeVariables);
		//Inicializo clausulas
		caso.clausulas.clear();		
		for (int i = 0; i < cantidadDeClausulas; i++) {
			caso.clausulas.add(new ArrayList<Integer>());
		}
		//Me aseguro de poner las variables en alguna clausula
		for (int i = 1; i < cantidadDeVariables+1; i++) {	
			int clausula = (int)(Math.random()*cantidadDeClausulas);
			boolean paridad = (int) ((Math.random() * 51)) % 2 == 0;
			if (paridad) {
				//Solo si no la contenia ya la pongo
				if (!caso.clausulas.get(clausula).contains(i)) {
					caso.clausulas.get(clausula).add(i);
				}
			} else {
				//Solo si no la contenia la pongo
				if (!caso.clausulas.get(clausula).contains(-i)) {
					caso.clausulas.get(clausula).add(-i);
				}
			}
			
			
		}
		
		for (int i = 0; i < cantidadDeClausulas; i++) {
			//Maxima cantidad de variables que puedo llegar a tener en una clausula, es un random entre 1 y la variacionDelRandom
			int cantidadaDeVarMax = (int)(Math.random()*(variacionDelRandom-1))+1;
			for (int variable = 1; variable < cantidadaDeVarMax +1; variable++) {
				//Decide si ponerla o no a la variable
				boolean lapongo = (int) ((Math.random() * 21)) % 2 == 0;
				//Decide que valor de verdad tendra
				boolean paridad = (int) ((Math.random() * 51)) % 2 == 0;
				if (lapongo) {
					if (paridad) {
						//Solo si no la contenia ya la pongo
						if (!caso.clausulas.get(i).contains(variable)) {
							caso.clausulas.get(i).add(variable);
						}
					} else {
						//Solo si no la contenia la pongo
						if (!caso.clausulas.get(i).contains(-variable)) {
							caso.clausulas.get(i).add(-variable);
						}
					}
				}
			}
		}
		
		return caso;
	}
	
	
	public CasoDePrueba generarCasoDePruebaConstructivoPeorCaso(int cantidadDeVariables,int cantidadDeClausulas,int variacionDelRandom){

		//Control
		if(variacionDelRandom>cantidadDeVariables){
			variacionDelRandom=cantidadDeVariables;
		}
		
		CasoDePrueba caso = new CasoDePrueba(cantidadDeClausulas,cantidadDeVariables);
		//Inicializo clausulas
		caso.clausulas.clear();		
		for (int i = 0; i < cantidadDeClausulas; i++) {
			caso.clausulas.add(new ArrayList<Integer>());
		}
		int cl = 0;
		while(cantidadDeVariables>0){
			caso.clausulas.get(cl).add(cantidadDeVariables);
			cl++;
			cantidadDeVariables--;
		}
						
		return caso;
	}
	
	public CasoDePrueba generarCasoDePruebaConstructivoPeorCasoVariandoClausulas(int cantidadDeVariables,int cantidadDeClausulas,int variacionDelRandom){

		//Control
		if(variacionDelRandom>cantidadDeVariables){
			variacionDelRandom=cantidadDeVariables;
		}
		
		CasoDePrueba caso = new CasoDePrueba(cantidadDeClausulas,cantidadDeVariables);
		//Inicializo clausulas
		caso.clausulas.clear();		
		for (int i = 0; i < cantidadDeClausulas; i++) {
			caso.clausulas.add(new ArrayList<Integer>());
		}
		//Me aseguro de poner las variables en alguna clausula
		for (int i = 1; i < cantidadDeVariables+1; i++) {	
			int clausula = (int)(Math.random()*cantidadDeClausulas);
			boolean paridad = (int) ((Math.random() * 51)) % 2 == 0;
			if (paridad) {
				//Solo si no la contenia ya la pongo
				if (!caso.clausulas.get(clausula).contains(i)) {
					caso.clausulas.get(clausula).add(i);
				}
			} else {
				//Solo si no la contenia la pongo
				if (!caso.clausulas.get(clausula).contains(-i)) {
					caso.clausulas.get(clausula).add(-i);
				}
			}
			
			
		}
						
		return caso;
	}

	
	public void escribirCasoDePrueba(ArrayList<CasoDePrueba> casosDePrueba) throws IOException{
		BufferedWriter bw = new BufferedWriter(new FileWriter("Tp3.in"));
		for (int i = 0; i < casosDePrueba.size(); i++) {
		CasoDePrueba casoDePrueba = casosDePrueba.get(i);	
		
			bw.append(casoDePrueba.c+" "+casoDePrueba.v);
			bw.newLine();
		for (int j = 0; j < casoDePrueba.clausulas.size(); j++) {
			
				ArrayList<Integer> clausula = casoDePrueba.clausulas.get(j);
				
				bw.append(clausula.size()+" ");
				
				for (Integer var : clausula) {
					bw.append(var+" ");
				}
				if(j+1<casoDePrueba.clausulas.size()){
					bw.newLine();
				}
			}
			bw.newLine();
		}
		bw.append("-1 -1");
		bw.close();
	}
	
}